1. Field of the Invention
The present invention relates generally to the development of computer programs, and in particular to a method and apparatus for statement level debugging of a computer program.
2. Description of the Related Art
There exist in the art many known techniques for developing software, also called computer programs, for execution on computer systems. Inherent in any software development technique is the detection and correction of logic errors, commonly referred to as "bugs". A bug will typically cause unexpected results during the execution of the program. The unexpected results may cause abnormal termination of the program or erroneous data to be generated.
Most computer programs today are developed using programming languages that are compiled versus programming languages that are interpreted. In a language that is compiled, the entire program must first be converted into a format that the computer system understands. Such a converted program is often called an object module. It is the object module that is then used to execute the program. Examples of compiled languages include C, PASCAL and Fortran.
In a language that is interpreted, each statement is converted into a machine readable format as it is being executed. Such interpreted languages first require that the computer system be placed in an "environment" in which the statements of the language are interpreted. Examples of such interpretive languages are BASIC, APL and LISP. Compiled and interpreted languages, and their differences are well known to those skilled in the art.
Of primary interest are compiled languages. The development of computer programs using a compiled language involves the basic steps of writing the code, compiling (or assembling) and linking the code into a format that is understandable to the underlying computer system, and debugging errors in the program. Often, it is the debugging step that is the most difficult and time consuming process.
Prior to continuing, it may be useful to refer to Appendix A for a description of terms that are used herein and that are well understood by those skilled in the art. In any event, certain terms are described herein for the sake of convenience.
Debugging of programs may be done either manually or interactively by a debugging system mediated by a computer system. In the manual debugging of a program, the logic flow of the program and the contents of storage elements, e.g. registers and variables, is traced manually. In the interactive debugging of programs, the program is executed under the control of a monitor program, commonly located on and executed by the same computer system on which the program is executed, which provides for introducing "breakpoints" in the program. During such breakpoints, program registers and variables may be examined. In such a manner the program can be suspended at key points of the program to determine the value of the storage elements. If a storage element contains a value that is inconsistent with expected results, then the developer knows that a "bug" in the program has been introduced.
In a second debugging technique, a programmer may suspend execution at the end of each logical grouping of instructions, e.g. a line of a source file. This is known as "stepping" through the execution of the code. The operation of "stepping" is as if a breakpoint has been specified at each line of the source file.
Known interactive debugging systems allow the introduction of breakpoints or program execution "stepping" at the source file line level (i.e. line level debugging). Such known interactive debugging systems include the XRAY family of debugging systems, available from MICROTEC RESEARCH INC. of Santa Clara, Calif. However, in many instances it is desirable to be able to set breakpoints or step through program execution at more precise points than available in line level debugging. As most computer languages provide for multiple "statements" to exist on a line of the source file, it is desirable to be able to debug at the statement level. Such advantages of statement level debugging will become apparent in the description of the currently preferred embodiment.
It may seem that statement level debugging may be accomplished by separating each statement onto it's own line. However, the syntax of some programming language statements do not lend themselves to doing this. An example is a FOR loop in the C programming language. A FOR loop has three discrete statements: a loop initialization statement, an iteration statement and a test statement. All three statements may be and are commonly found on the same source line. A programmer typically places them on the same source line in order to make the FOR loop more legible. In all cases, separation of statements would require editing of the source file and the re-compilation and re-linking of the program. In many instances this is not feasible or desirable. In a very large program the compilation and linking steps could be very complex and time consuming. Generally, breakpoints are set based on results found in prior breakpoints i.e. breakpoints are set dynamically during the interactive debugging process. If the re-compilation and re-linking had to take place in order to introduce breakpoints, much time could be wasted, and more importantly, the developers mental thought process would be disrupted.
In order to suspend execution at a predetermined breakpoint, certain debugging information is needed for cross-referencing a line in the source code file with an address in the machine executable code. Debugging information is provided to the debugging system from portions of the object module. Typically, the debugging information is generated by the compiler used to generate the object module. As the generation of the debugging information causes the creation of a larger object module, as well as extending the compilation time, such debugging information is normally not generated. To cause the compiler to create such debugging information, a special compiler debugging option is specified.
Once the debugging system is provided with debugging information, it must process it so it can be used for breakpoints, program stepping or other debugging operations. Further, the debugging system must have a user interface through which a user may invoke the desired debugging operation.
There exist in the art various standards for object module formats. However, none of the standards address all of the provisions of debugging information. One standard format for object modules is defined by the International Institute of Electrical and Electronics Engineers (IEEE) 695 standard entitled "IEEE Standard for Microprocessor Universal Format for Object Modules." A purpose of the IEEE 695 standard is to provide for portability of object modules across microprocessor based computing platforms.
Other known standardized object module formats include COFF, ELF, A.OUT and OMF86. CO FF, A.OUT and ELF are object module formats directed towards execution on UNIX.RTM. (a registered trademark of American Telephone & Telegraph) based computer systems. The OMF86 object code format is directed towards object modules that execute on computer systems utilizing microprocessors based on the Intel family of microprocessors (e.g. the Intel 8086, 80186, 80286, 80386 and 80486 microprocessors).
Thus, it is an object of the present invention to provide the necessary debugging information in an object module for distinguishing statements in a line of a source file. It is a further object of the present invention to utilize such debugging information so as to enable statement level debugging by a debugging system. Finally, it is an object of the present invention to provide a means by which statement level breakpoints may be set.